package ModelLayer;

import java.util.ArrayList;
import java.io.Serializable;
import java.util.Date;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;

public class Sale implements Serializable {

	private static final long serialVersionUID = 1L;
	private static int lastid;
	private int id;
	private Customer customer;
	private Status status;
	private Status payStatus;
	private boolean pickup;
	private Employee employee;
	private double finalPrice;
	private long startDate;
	private String dAddress;
	private ArrayList<SalesLine> saleLines;
	private static final double MAXDISCOUNT = 0.2;

	// constructor with arguments
	public Sale(int customerId, int employeeId, long startDate)
			throws RealException {
		this.startDate = startDate;
		setStatus(Status.Offer);
		setPayStatus(Status.Unpaid);
		setId(getNewId());
		finalPrice = 0;
		customer = CustomerRecords.getInstance().getCustomer(customerId);
		employee = EmployeeRecords.getInstance().getEmployee(employeeId);
		saleLines = new ArrayList<SalesLine>();
	}

	// empty constructor
	public Sale() {
		setId(getNewId());
		setStatus(Status.Offer);
		setPayStatus(Status.Unpaid);
		finalPrice = 0;
		saleLines = new ArrayList<SalesLine>();
	}

	// return a price with different discount, if bonus doesn't exceed maximum
	// discount (20%)
	// otherwise return a price with maximum discount 20%
	public void endSale() throws RealException {
		double finalPrice;
		double totalPriceWithMaxDiscount = getTotalPriceWithoutDiscount()
				* (1 - Sale.getMaxdiscount());
		double totalPriceWithDiscount = getTotalPriceWithDiscount();
		if (totalPriceWithMaxDiscount > totalPriceWithDiscount) {
			finalPrice = totalPriceWithMaxDiscount;
		} else {
			finalPrice = totalPriceWithDiscount;
		}
		setFinalPrice(finalPrice);
	}

	public double getTotalPriceWithoutDiscount() throws RealException {
		double totalPriceWithoutDiscount = 0;
		if (saleLines.size() != 0) {
			for (SalesLine salesLine : saleLines) {
				totalPriceWithoutDiscount += salesLine
						.getSubtotalWithoutDiscount();
			}
		}
		return totalPriceWithoutDiscount;
	}

	public double getTotalPriceWithDiscount() throws RealException {
		double totalPriceWithDiscount = 0;
		if (saleLines.size() != 0) {
			for (SalesLine salesLine : saleLines) {
				totalPriceWithDiscount += salesLine.getSubtotalWithDiscount();
			}
		}
		return totalPriceWithDiscount;
	}

	public boolean exceedMaxDiscount() throws RealException {
		if (getTotalDiscount() > 0.2) {
			return true;
		}
		return false;
	}

	public double getTotalDiscount() throws RealException {
		double discount = 0.0;
		if (getTotalPriceWithoutDiscount() != 0.0)
			discount = 1 - getTotalPriceWithDiscount()
					/ getTotalPriceWithoutDiscount();
		return discount;
	}

	// add a sales-line to sale
	public void addSalesLine(int quantity, String barcode) throws RealException {

		SalesLine saleline = new SalesLine(this, quantity, barcode);
		saleLines.add(saleline);
		if (getStatus() == Status.Order) {
			saleline.getSaleItem().setCurrStock(
					saleline.getSaleItem().getCurrStock() - quantity);
		}
		saleline.calculateSubtotalWithoutDiscount();
		saleline.calculateSubtotalWithDiscount();
		endSale();

	}

	// remove a sales-line to Sale
	public void removeSalesLine(String barcode) throws RealException {

		SalesLine salesLine = getSalesLine(barcode);
		if (salesLine != null) {
			saleLines.remove(salesLine);
			if (getStatus() == Status.Order) {
				salesLine.getSaleItem().setCurrStock(
						salesLine.getSaleItem().getCurrStock()
								+ salesLine.getQuantity());
			}
			endSale();
		} else {
			throw new RealException("Salesline not found!");
		}
	}

	public void deleteSale() {
		if (saleLines.size() != 0) {
			for (SalesLine saleLine : saleLines) {
				saleLine.getSaleItem().setCurrStock(
						saleLine.getSaleItem().getCurrStock()
								+ saleLine.getQuantity());
			}
		}
	}

	// return a salesline
	public SalesLine getSalesLine(String barcode) throws RealException {
		for (SalesLine salesLine : saleLines) {
			if (salesLine.getBarcode().equals(barcode))
				return salesLine;
		}
		throw new RealException("Salesline not found!");
	}

	public void confirmOffer() throws RealException {

		if (getStatus() == Status.Offer) {
			setStartDate(getCurrentDate());
			for (SalesLine saleLine : saleLines) {
				saleLine.getSaleItem().setCurrStock(
						saleLine.getSaleItem().getCurrStock()
								- saleLine.getQuantity());
			}
			setStatus(Status.Order); // change to order
		} else {
			throw new RealException("This is not an offer.");
		}
	}

	public void confirmPayment() throws RealException {
		if (getPayStatus() == Status.Unpaid) {
			setPayStatus(Status.Paid);
		} else {
			throw new RealException(
					"The order has been paied. You can not confirm it again. ");
		}
	}

	// print all salelines information for a sale
	public String listAllSalelines() {
		String description = "";
		for (SalesLine salesLine : saleLines) {
			description += salesLine.toString();
		}
		try {
			description += "Total price without discount : "
					+ Double.valueOf(new DecimalFormat("#.##")
							.format(getTotalPriceWithoutDiscount()))
					+ "\nTotal price with discount: "
					+ Double.valueOf(new DecimalFormat("#.##")
							.format(getTotalPriceWithDiscount()))
					+ ", Discount: "
					+ Double.valueOf(new DecimalFormat("#.##")
							.format(getTotalDiscount() * 100)) + "%";
			if (exceedMaxDiscount()) {
				description += "\nThe discount exceeds the max discount (20%)"
						+ "\n\nFinal price: " + getFinalPrice();
			}
		} catch (RealException e) {
		}
		return description;
	}

	// convert date from long to string type
	public String convertDate(long date) {
		String orderDate = new SimpleDateFormat("dd/MM/yyyy").format(new Date(
				date));
		return orderDate;
	}

	public void setDate(long date) {
		startDate = date;
	}

	public String getDate() {
		return convertDate(startDate);
	}

	// return current day
	public long getCurrentDate() {
		Calendar cal = Calendar.getInstance();
		java.util.Date utilDate = cal.getTime();
		return utilDate.getTime();
	}

	public int getMonth() {
		Date date = new Date(startDate);
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int month = cal.get(Calendar.MONTH) + 1;
		return month;
	}

	public int getYear() {
		Date date = new Date(startDate);
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int year = cal.get(Calendar.YEAR);
		return year;
	}

	// print information about a sale
	public String toString() {
		String description;
		String delivery;
		if (pickup) {
			delivery = "Self pickup";
		} else {
			delivery = dAddress;
		}
		description = "\n\nId: " + id + "\nCustomer: " + customer.getName()
				+ "\nEmployee: " + employee.getName() + "\nStatus: "
				+ getStatus().toString() + "\nDate: " + convertDate(startDate)
				+ "\nDelivery: " + delivery + "\nPayment Term: "
				+ customer.getGroup().getPaymentTerm();
		if (saleLines.size() != 0) {
			for (SalesLine salesLine : saleLines) {
				description += salesLine.toString();
			}
		}
		try {
			description = description
					+ "\n\nTotal price without discount : "
					+ Double.valueOf(new DecimalFormat("#.##")
							.format(getTotalPriceWithoutDiscount()))
					+ "\nTotal price with discount: "
					+ Double.valueOf(new DecimalFormat("#.##")
							.format(getTotalPriceWithDiscount()))
					+ ", Discount: "
					+ Double.valueOf(new DecimalFormat("#.##")
							.format(getTotalDiscount() * 100)) + "%";
			if (exceedMaxDiscount()) {
				description = description
						+ "\nThe discount exceeds the max discount (20%)"
						+ "\n\nFinal price: " + getFinalPrice();
			}
		} catch (RealException e) {
		}
		if (getStatus() == Status.Order)
			description += "\nPay Status: " + payStatus.toString();
		return description;
	}

	// get new distinct id
	public static int getNewId() {
		return ++lastid;
	}

	public static void setLastId(int lastId) {
		lastid = lastId;
	}

	public static int getLastId() {
		return lastid;
	}

	public int getId() {
		return id;
	}

	public void setStartDate(long startDate) {
		this.startDate = startDate;
	}

	public long getStartDay() {
		return startDate;
	}

	public void setId(int id) {
		this.id = id;
	}

	public void setPickup(boolean pickup) {
		this.pickup = pickup;
	}

	public boolean getPickup() {
		return pickup;
	}

	public Customer getCustomer() {
		return customer;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}

	public ArrayList<SalesLine> getSaleLines() {
		return saleLines;
	}

	public void setSaleLines(ArrayList<SalesLine> saleLines) {
		this.saleLines = saleLines;
	}

	public void setStatus(Status status) {
		this.status = status;
	}

	public Status getStatus() {
		return status;
	}

	public Employee getEmployee() {
		return employee;
	}

	public void setEmployee(Employee employee) {
		this.employee = employee;
	}

	public double getFinalPrice() {
		return finalPrice;
	}

	public void setFinalPrice(double finalPrice) {
		this.finalPrice = finalPrice;
	}

	public static double getMaxdiscount() {
		return MAXDISCOUNT;
	}

	public String getdAddress() {
		return dAddress;
	}

	public void setdAddress(String dAddress) {
		this.dAddress = dAddress;
	}

	public Status getPayStatus() {
		return payStatus;
	}

	public void setPayStatus(Status payStatus) {
		this.payStatus = payStatus;
	}

}
